#############################################################################
#
# Buienradar (Dutch weather radar)
#
# Created by: rodejo (rodejo16@gmail.com). Based on Navi-X
#
# Version 1.0
#
#############################################################################

from string import *
import sys, os.path
import urllib
import re, random, string
import xbmc, xbmcgui
import re, os, time, time, traceback
import Image, ImageFile
import shutil
import zipfile
import threading

try: Emulating = xbmcgui.Emulating
except: Emulating = False

ACTION_MOVE_LEFT       =  1 #Dpad Left
ACTION_MOVE_RIGHT      =  2 #Dpad Right
ACTION_MOVE_UP         =  3 #Dpad Up
ACTION_MOVE_DOWN       =  4 #Dpad Down
ACTION_PAGE_UP         =  5 #Left trigger
ACTION_PAGE_DOWN       =  6 #Right trigger
ACTION_SELECT_ITEM     =  7 #'A'
ACTION_HIGHLIGHT_ITEM  =  8
ACTION_PARENT_DIR      =  9 #'B'
ACTION_PREVIOUS_MENU   = 10 #'Back'
ACTION_SHOW_INFO       = 11
ACTION_PAUSE           = 12
ACTION_STOP            = 13 #'Start'
ACTION_NEXT_ITEM       = 14
ACTION_PREV_ITEM       = 15
ACTION_XBUTTON	       = 18 #'X'
ACTION_CONTEXT_MENU    = 117 # pops up the context menu


#############################################################################
# autoscaling values
#############################################################################

HDTV_1080i = 0      #(1920x1080, 16:9, pixels are 1:1)
HDTV_720p = 1       #(1280x720, 16:9, pixels are 1:1)
HDTV_480p_4x3 = 2   #(720x480, 4:3, pixels are 4320:4739)
HDTV_480p_16x9 = 3  #(720x480, 16:9, pixels are 5760:4739)
NTSC_4x3 = 4        #(720x480, 4:3, pixels are 4320:4739)
NTSC_16x9 = 5       #(720x480, 16:9, pixels are 5760:4739)
PAL_4x3 = 6         #(720x576, 4:3, pixels are 128:117)
PAL_16x9 = 7        #(720x576, 16:9, pixels are 512:351)
PAL60_4x3 = 8       #(720x480, 4:3, pixels are 4320:4739)
PAL60_16x9 = 9      #(720x480, 16:9, pixels are 5760:4739)

######################################################################
Version='1' #program version
SubVersion='0'

RootDir = os.getcwd()
if RootDir[-1]==';': RootDir=RootDir[0:-1]
if RootDir[-1]!='\\': RootDir=RootDir+'\\'
imageDir = RootDir + "\\images\\"
cacheDir = RootDir + "\\cache\\"
imageCacheDir = RootDir + "\\cache\\imageview\\"
scriptDir = "Q:\\scripts\\"
initDir = RootDir + "\\init\\"

favorite_file='favorites.plx' #the favorite list is also a playlist
downloads_file='downloads.plx' #the downloads list is also a playlist
plxVersion = '3'
home_URL='http://home.planet.nl/~jon70928/home.plx'

class Timer(threading.Thread):
    def __init__(self, *args, **kwargs):
        if (kwargs.has_key('function')): 
            self.function = kwargs['function']
            
            self.kill = 0

        threading.Thread.__init__(self)
    def run(self):
        while self.kill == 0:
            time.sleep(0.8) #delay 1 second
            self.function(0) #call callback function
        
        self.kill = 2
            
    def kill(self):
        self.kill = 1
        
    def status(self):
        return self.kill
       

######################################################################
# Description: Playlist item class. 
######################################################################
class CMediaItem:
    def __init__(self, id='0', type='unknown', version=plxVersion, name='', thumb='default', URL=''):
        self.id = id        #identifier
        self.type = type    #type (playlist, image, video, audio, text)
        self.version = version #playlist version
        self.name = name    #name as displayed in list view
        self.thumb = thumb  #URL to thumb image or 'default'
        self.URL = URL      #URL to playlist entry

######################################################################
# Description: Playlist item class. 
######################################################################
class CHistorytem:
    def __init__(self, URL='', index=0):
        self.URL = URL        
        self.index = index        

######################################################################
# Description: Downloads a URL to local disk. 
######################################################################
class CFileLoader:
    ######################################################################
    # Description: Downloads a file in case of URL and returns absolute
    #              path to the local file.
    # Parameters : URL=source, localfile=destination
    # Return     : -
    ######################################################################
    def load(self, URL, localfile):
        if URL[:4] == 'http':
            try:
                loc = urllib.URLopener()
                loc.retrieve(URL, localfile)
            except IOError:
                self.state = -1 #failed
                return
            self.state = 0 #success
            self.localfile = localfile
        elif URL[1] == ':': #absolute path
            self.localfile = URL
            self.state = 0 #success
        else: #assuming relative path
            self.localfile = RootDir + '\\' + URL
            self.state = 0 #success


######################################################################
# Description: Text viewer
######################################################################
class CTextView(xbmcgui.Window):
    def __init__(self):
        self.setCoordinateResolution(PAL_4x3)
    
        #background image
        self.bg = xbmcgui.ControlImage(0,0,720,576, imageDir + "background_txt.png")
        self.addControl(self.bg)
        
        self.TextBox = xbmcgui.ControlTextBox(60, 50, 600, 460)
        self.addControl(self.TextBox)
        self.TextBox.setVisible(1)
        
        self.setFocus(self.TextBox)
       
    def onAction(self, action):
        if action == ACTION_PREVIOUS_MENU or action == ACTION_PARENT_DIR:
            self.close()
            
    def onControl(self, control):
        self.setFocus(control)
        
    def OpenDocument(self, filename):
        loader = CFileLoader()
        loader.load(filename, cacheDir + 'document.txt')
        if loader.state == 0:
            #download or open the file
            f=open(loader.localfile, 'r')
            data = f.read()
            f.close()
            self.TextBox.setText(data)
            return 0 #success
        else:
            dialog = xbmcgui.Dialog()
            dialog.ok("Error", "Could not open file.")
            return -1 #failure

######################################################################
# Description: Main Window class
######################################################################
class MainWindow(xbmcgui.Window):
        def __init__(self):
            if Emulating: xbmcgui.Window.__init__(self)
            if not Emulating:
                self.setCoordinateResolution(PAL_4x3)

            #Create DIRs
            if not os.path.exists(cacheDir): 
                os.mkdir(cacheDir) 
#            if not os.path.exists(myDownloadsDir): 
#                os.mkdir(myDownloadsDir) 

            #background image
            self.bg = xbmcgui.ControlImage(0,0,720,576, imageDir + "background.png")
            self.addControl(self.bg)

            #map image
            self.mb = xbmcgui.ControlImage(195,110,485,410, imageDir + "map_nl.jpg")
            self.addControl(self.mb)

            #buienradar images
            self.bi = xbmcgui.ControlImage(195,110,485,410, imageDir + "map_nl.jpg")
            self.addControl(self.bi)

            #buienradar logo at top-left position
            #self.logo = xbmcgui.ControlImage(30,20,720,85, imageDir + "logo.jpg")
            #self.addControl(self.logo)
            
            #buienradar logo at top-left position
            #self.user_logo = xbmcgui.ControlImage(55,315,140,150, imageDir + "logo.png")
            #self.addControl(self.user_logo)
            #self.user_logo.setVisible(0)
            
            #Date/Time label
            self.version = xbmcgui.ControlLabel(55,480,545,40, 'Version: '+ Version+ '.' + SubVersion, "font14")
            self.addControl(self.version)      

            #buttons creation
            self.button_NL = xbmcgui.ControlButton(40,145,128,32,' Radar NL', RootDir + "images\\button-focus.png", RootDir + "images\\button-nofocus.png")
            self.addControl(self.button_NL)
            self.button_EUR = xbmcgui.ControlButton(40,175,128,32,' Radar Europa', RootDir + "images\\button-focus.png", RootDir + "images\\button-nofocus.png")            
            self.addControl(self.button_EUR)            
            
            #button key behaviour
            self.button_NL.controlDown(self.button_EUR)
            self.button_EUR.controlUp(self.button_NL)

            self.state_busy = 0 # busy state
            
            self.loader = CFileLoader() #file loader

            self.onDownload_NL()
            self.setFocus(self.button_NL)
            
            self.tick = 0
            self.task = Timer(function=self.myPlayerChanged)
            self.task.start()
            self.kill = 0

################################################################
################################################################
        def onDownload_NL(self):
        
            self.mb.setImage(imageDir + "map_nl.jpg")
            self.bi.setImage(imageDir + "map_nl.jpg")
         
            self.hold = True
         
            now = time.localtime(time.time())
            year, month, day, hour, minute, second, weekday, yearday, daylight = now
            
            str_month= '%02d'%(month)
            str_day='%02d'%(day)

            hour = hour - 1
            minute = minute - (minute % 5)
            
            for i in range(11):
               
                str_hour= '%02d'%(hour)
                str_minute='%02d'%(minute)
                
                t = "jaar=" + str(year) + "&maand=" + str_month + "&dag=" + str_day + "&minuut=" + str_minute + "&uur=" + str_hour + "&bliksem=0"            
                self.loader.load("http://www.buienradar.nl/images.aspx?" + t, cacheDir + "image" + str(i) + ".gif")

                minute = minute + 5
                if minute == 60:
                    minute = 0
                    hour = hour + 1

            #image have been downloaded. Now display them in sequence
            self.bi.setImage(cacheDir + "image0.gif")
          
            self.tick = 0          
            self.hold = False
          
################################################################
################################################################
        def onDownload_EUR(self):
        
            self.mb.setImage(imageDir + "map_eur.jpg")
            self.bi.setImage(imageDir + "map_eur.jpg")

            self.hold = True
         
            now = time.localtime(time.time())
            year, month, day, hour, minute, second, weekday, yearday, daylight = now
            
            str_month= '%02d'%(month)
            str_day='%02d'%(day)

            hour = hour - 3
            minute = minute - (minute % 15)
            minute = minute + 15
            if minute == 60:
                hour = hour + 1
                minute = 0
            
            for i in range(11):
               
                str_hour= '%02d'%(hour)
                str_minute='%02d'%(minute)
                
                t = "jaar=" + str(year) + "&maand=" + str_month + "&dag=" + str_day + "&minuut=" + str_minute + "&uur=" + str_hour + "&bliksem=0"            
                self.loader.load("http://www.meteox.nl/images.aspx?" + t, cacheDir + "image" + str(i) + ".gif")

                minute = minute + 15
                if minute == 60:
                    minute = 0
                    hour = hour + 1

            #image have been downloaded. Now display them in sequence
            self.bi.setImage(cacheDir + "image0.gif")
          
            self.tick = 0          
            self.hold = False
          
        ######################################################################
        # Description: Handles key events.
        # Parameters : action=user action
        # Return     : -
        ######################################################################
        def onAction(self, action):
            self.state_action = 1
            
            if action == ACTION_PREVIOUS_MENU:
                
                self.kill = 1
                self.delFiles(cacheDir) #clear the cache first
                self.close() #exit
                
            if self.state_busy == 0:
                if action == ACTION_SELECT_ITEM:
                    if self.getFocus() == self.button_NL:
                        self.onDownload_NL()
                    #favorite button
                    elif self.getFocus() == self.button_EUR:
                        self.onDownload_EUR()
#                elif action == ACTION_PARENT_DIR:

        ######################################################################
        # Description: Handles UI events.
        # Parameters : control=handle to UI control
        # Return     : -
        ######################################################################
        def onControl(self, control):
            pass
                
        ######################################################################
        # Description: Download file to local cache.
        # Parameters : URL=URL to source file
        #              localfile=path+name of local (destination) file
        # Return     : 0=succes, -1=failed
        ######################################################################
        def downloadFile(self, URL, localfile):
            try:
                loc = urllib.URLopener()
                loc.retrieve(URL, localfile)
            except IOError:
                return -1
            return 0

        ######################################################################
        # Description: Player changed info can be catched here
        # Parameters : action=user key action
        # Return     : -
        ######################################################################
        def myPlayerChanged(self, state):
            if self.kill == 1:
                self.task.kill()
            elif self.hold == False:
                self.tick = self.tick + 1
                if self.tick >= 11:
                    self.tick = 0
                    time.sleep(0.8) #delay 1 second
                
                self.bi.setImage(cacheDir + "image" + str(self.tick) + ".gif")
            
            now = time.localtime(time.time())

            self.version.setLabel(time.strftime("%d/%m/%y %H:%M", now))
            
           
        ######################################################################
        # Description: Handles display of a text file.
        # Parameters : -
        # Return     : -
        ######################################################################
        def OpenTextFile( self, URL):
            textwnd = CTextView()
            result = textwnd.OpenDocument(URL)
            if result == 0:
                textwnd.doModal()
                
        ######################################################################
        # Description: Handles image viewing.
        # Parameters : playlist=the source playlist
        #              pos=media item position in the playlist
        #              mode=view mode (0=slideshow, 1=recursive slideshow)
        #              URL = URL to image
        # Return     : -
        ######################################################################
        def viewImage(self, playlist, pos, mode, iURL=''):
            if self.state_busy == 1:
                return
            
            self.state_busy = 1
        
            self.infotekst.setVisible(1)
            #clear the imageview cache
            self.delFiles(imageCacheDir)

            if not os.path.exists(imageCacheDir): 
                os.mkdir(imageCacheDir) 

            if mode == 0: #single file show
                localfile= imageCacheDir + '0.'
                if iURL != '':
                    URL = iURL
                else:    
                    URL = playlist.list[pos].URL
                ext = self.getFileEntension(URL)

                if URL[:4] == 'http':
                    self.loader.load(URL, localfile + ext)
                    if self.loader.state == 0:
                        xbmc.executebuiltin('xbmc.slideshow(' + imageCacheDir + ')')
                else:
                    #local file
                    shutil.copyfile(URL, localfile + ext)
                    xbmc.executebuiltin('xbmc.slideshow(' + imageCacheDir + ')')
            
            elif mode == 1: #recursive slideshow
                #in case of slideshow store default image
                count=0
                for i in range(self.list.size()):
                    if playlist.list[i].type == 'image':
                        localfile=imageCacheDir+'%d.'%(count)
                        URL = playlist.list[i].URL
                        ext = self.getFileEntension(URL)
                        shutil.copyfile(imageDir+'imageview.png', localfile + ext)
                        count = count + 1
                if count > 0:
                    count = 0
                    for i in range(self.list.size()):
                        if count == 2:
                            xbmc.executebuiltin('xbmc.recursiveslideshow(' + imageCacheDir + ')')
                            self.state_action = 0
                        elif count > 2 and self.state_action == 1:
                            break
                            
                        if playlist.list[i].type == 'image':
                            localfile=imageCacheDir+'%d.'%(count)
                            URL = playlist.list[i].URL
                            ext = self.getFileEntension(URL)
                            self.loader.load(URL, localfile + ext)
                            if self.loader.state == 0:
                                count = count + 1

                    if self.list.size() < 3:
                        #start the slideshow after the first two files. load the remaining files
                        #in the background
                        xbmc.executebuiltin('xbmc.recursiveslideshow(' + imageCacheDir + ')')
                if count == 0:
                    dialog = xbmcgui.Dialog()
                    dialog.ok("Error", "No images in playlist.")
            
            self.infotekst.setVisible(0)
            
            self.state_busy = 0

        ######################################################################
        # Description: Get the file extension of a URL
        # Parameters : filename=local path + file name
        # Return     : -
        ######################################################################
        def getFileEntension(self, filename):
            ext_pos = filename.rfind('.') #find last '.' in the string
            if ext_pos != -1:
                return filename[ext_pos+1:]
            else:
                return ''
                
        ######################################################################
        # Description: Deletes all files in a given folder and sub-folders.
        #              Note that the sub-folders itself are not deleted.
        # Parameters : folder=path to local folder
        # Return     : -
        ######################################################################
        def delFiles(self, folder):
            for root, dirs, files in os.walk(folder , topdown=False):
                for name in files:
                    os.remove(os.path.join(root, name))
                    

win = MainWindow()
win.doModal()
del win
